
package com.yuanmei.datas;

import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;
import io.realm.Sort;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import com.yuanmei.model.HistoryDayQuote;
import com.yuanmei.model.HistoryHourQuote;
import com.yuanmei.model.HistoryMonthQuote;
import com.yuanmei.model.HistoryWeekQuote;
import com.yuanmei.model.TickQuote;
import com.yuanmei.common.Utils;
import com.yuanmei.model.TodayQuote;
/*
td.get_k_data('600848', '1990-01-01', '2019-02-21', 'D', None)
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day1990&param=sh600848,day,1990-01-01,1991-12-31,640,&r=0.31043928536668521
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day1992&param=sh600848,day,1992-01-01,1993-12-31,640,&r=0.40414444418878706
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day1994&param=sh600848,day,1994-01-01,1995-12-31,640,&r=0.57656405672986428
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day1996&param=sh600848,day,1996-01-01,1997-12-31,640,&r=0.85966057282815141
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day1998&param=sh600848,day,1998-01-01,1999-12-31,640,&r=0.95586761898354587
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2000&param=sh600848,day,2000-01-01,2001-12-31,640,&r=0.81552795456970892
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2002&param=sh600848,day,2002-01-01,2003-12-31,640,&r=0.96044637565039271
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2004&param=sh600848,day,2004-01-01,2005-12-31,640,&r=0.52708774952656481
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2006&param=sh600848,day,2006-01-01,2007-12-31,640,&r=0.39644307024287342
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2008&param=sh600848,day,2008-01-01,2009-12-31,640,&r=0.39669786619590961
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2010&param=sh600848,day,2010-01-01,2011-12-31,640,&r=0.91281815115490571
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2012&param=sh600848,day,2012-01-01,2013-12-31,640,&r=0.95072371407868114
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2014&param=sh600848,day,2014-01-01,2015-12-31,640,&r=0.48947391142261785
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2016&param=sh600848,day,2016-01-01,2017-12-31,640,&r=0.88623112630694938
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day2018&param=sh600848,day,2018-01-01,2019-12-31,640,&r=0.28490860379037564


td.get_k_data('600848', '1990-01-01', '2019-02-21', 'D', 'qfq')
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq1990&param=sh600848,day,1990-01-01,1991-12-31,640,qfq&r=0.59622905324169434
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq1992&param=sh600848,day,1992-01-01,1993-12-31,640,qfq&r=0.96567312047136671
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq1994&param=sh600848,day,1994-01-01,1995-12-31,640,qfq&r=0.67777455271706015
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq1996&param=sh600848,day,1996-01-01,1997-12-31,640,qfq&r=0.51381193798338287
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq1998&param=sh600848,day,1998-01-01,1999-12-31,640,qfq&r=0.90520234733755015
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2000&param=sh600848,day,2000-01-01,2001-12-31,640,qfq&r=0.83696475714038441
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2002&param=sh600848,day,2002-01-01,2003-12-31,640,qfq&r=0.24143258784233722
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2004&param=sh600848,day,2004-01-01,2005-12-31,640,qfq&r=0.78854170794759902
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2006&param=sh600848,day,2006-01-01,2007-12-31,640,qfq&r=0.63891506876363167
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2008&param=sh600848,day,2008-01-01,2009-12-31,640,qfq&r=0.58501077446364060
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2010&param=sh600848,day,2010-01-01,2011-12-31,640,qfq&r=0.95334105094103980
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2012&param=sh600848,day,2012-01-01,2013-12-31,640,qfq&r=0.96963662509083881
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2014&param=sh600848,day,2014-01-01,2015-12-31,640,qfq&r=0.19720607076475827
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2016&param=sh600848,day,2016-01-01,2017-12-31,640,qfq&r=0.78343703000439885
JKP _get_k_data url=http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_dayqfq2018&param=sh600848,day,2018-01-01,2019-12-31,640,qfq&r=0.52364669991866242


获取15分钟线数据
'http://ifzq.gtimg.cn/appstock/app/kline/mkline?param=sz002808,m15,,64&_var=m5_today'

m5_today={"code":0,"msg":"","data":{"sz002808":{"qt":{"sz002808":["51","\u6052\u4e45\u79d1\u6280","002808","18.79","18.51","18.85","27674","14812","12819","18.72","19","18.67","2","18.65","10","18.64","30","18.63","114","18.79","18","18.80","12","18.81","17","18.82","68","18.84","22","11:19:24\/18.79\/4\/B\/7516\/7286|11:19:04\/18.72\/1\/S\/1872\/7264|11:19:01\/18.79\/2\/B\/3758\/7262|11:18:42\/18.71\/3\/B\/5613\/7242|11:18:40\/18.71\/15\/S\/28121\/7241|11:18:36\/18.78\/21\/S\/39438\/7237","20190423111925","0.28","1.51","19.18","18.54","18.79\/27669\/52131609","27674","5214","3.16","105.32","","19.18","18.54","3.46","16.45","36.08","6.50","20.36","16.66","0.98","38","18.84","114.90","118.49","","","0.59","5214.10"],"market":["2019-04-23 11:19:01|HK_open_\u4ea4\u6613\u4e2d|SH_open_\u4ea4\u6613\u4e2d|SZ_open_\u4ea4\u6613\u4e2d|US_close_\u5df2\u6536\u76d8|UK_close_\u672a\u5f00\u76d8|SQ_open_\u4ea4\u6613\u4e2d|DS_open_\u4ea4\u6613\u4e2d|ZS_open_\u4ea4\u6613\u4e2d|NEWSH_open_\u4ea4\u6613\u4e2d|NEWSZ_open_\u4ea4\u6613\u4e2d|NEWHK_open_\u4ea4\u6613\u4e2d|NEWUS_close_\u5df2\u6536\u76d8|REPO_open_\u4ea4\u6613\u4e2d"],"zjlx":["sz002808","84.46","0.00","84.46","3.18","2570.23","2296.01","274.23","11.94","52130000.00","2969.82","1869.49","\u6052\u4e45\u79d1\u6280","20190423","20190422^655.95^93.65","20190419^647.88^589.15","20190418^91.23^219.15","20190417^1490.29^967.53","44500.00","2583200.00","20190423111922"]},"m15":[["201904171315","19.33","19.34","19.38","19.28","1397.00",{},"15.9587"],["201904171330","19.34","19.27","19.36","19.27","2231.00",{},"25.4860"],["201904171345","19.27","19.19","19.28","19.12","2163.00",{},"24.7092"],["201904171400","19.19","19.15","19.25","19.14","1899.00",{},"21.6933"],["201904171415","19.15","19.22","19.24","19.11","2869.00",{},"32.7742"],["201904171430","19.22","19.16","19.22","19.11","2418.00",{},"27.6222"],["201904171445","19.16","19.02","19.16","19.00","3212.00",{},"36.6925"],["201904171500","19.02","19.00","19.12","19.00","4363.00",{},"49.8410"],["201904180945","19.20","18.96","19.23","18.94","7291.00",{},"83.2892"],["201904181000","18.96","18.87","19.04","18.79","6712.00",{},"76.6750"],["201904181015","18.87","18.88","18.88","18.66","5728.00",{},"65.4342"],["201904181030","18.88","18.98","19.00","18.82","2797.00",{},"31.9517"],["201904181045","18.98","19.02","19.03","18.90","2000.00",{},"22.8471"],["201904181100","19.02","19.16","19.29","19.00","5417.00",{},"61.8814"],["201904181115","19.16","19.14","19.17","19.05","2510.00",{},"28.6731"],["201904181130","19.14","19.07","19.23","19.00","3309.00",{},"37.8006"],["201904181315","19.07","18.91","19.09","18.80","2188.00",{},"24.9948"],["201904181330","18.91","18.94","19.00","18.91","1353.00",{},"15.4561"],["201904181345","18.94","18.96","18.96","18.85","2745.00",{},"31.3577"],["201904181400","18.96","18.90","18.99","18.90","1326.00",{},"15.1476"],["201904181415","18.90","18.79","18.94","18.77","4792.00",{},"54.7417"],["201904181430","18.79","18.71","18.83","18.66","7125.00",{},"81.3929"],["201904181445","18.71","18.79","18.93","18.69","2953.00",{},"33.7338"],["201904181500","18.79","18.86","18.87","18.68","4292.00",{},"49.0299"],["201904190945","18.97","18.70","19.06","18.47","7417.00",{},"84.7286"],["201904191000","18.70","18.74","18.80","18.67","2531.00",{},"28.9130"],["201904191015","18.74","18.79","18.87","18.71","3257.00",{},"37.2066"],["201904191030","18.79","18.69","18.88","18.63","4556.00",{},"52.0458"],["201904191045","18.69","18.74","18.88","18.63","5035.00",{},"57.5176"],["201904191100","18.74","18.94","18.99","18.67","4197.00",{},"47.9447"],["201904191115","18.94","18.99","19.08","18.87","2700.00",{},"30.8436"],["201904191130","18.99","18.98","19.02","18.83","891.00",{},"10.1784"],["201904191315","18.98","18.88","19.10","18.88","2735.00",{},"31.2434"],["201904191330","18.88","18.99","19.01","18.88","1018.00",{},"11.6292"],["201904191345","18.99","19.04","19.08","18.94","2260.00",{},"25.8173"],["201904191400","19.04","18.98","19.04","18.92","1519.00",{},"17.3524"],["201904191415","18.98","18.94","19.03","18.91","1359.00",{},"15.5246"],["201904191430","18.94","18.92","18.97","18.89","2313.00",{},"26.4227"],["201904191445","18.92","18.78","18.92","18.78","3313.00",{},"37.8463"],["201904191500","18.78","18.74","18.85","18.67","4319.00",{},"49.3384"],["201904220945","19.17","18.90","19.17","18.68","10017.00",{},"114.4298"],["201904221000","18.90","18.92","18.99","18.78","5768.00",{},"65.8911"],["201904221015","18.92","19.03","19.07","18.90","3806.00",{},"43.4781"],["201904221030","19.03","19.03","19.07","18.94","2629.00",{},"30.0326"],["201904221045","19.03","19.00","19.16","18.99","3307.00",{},"37.7777"],["201904221100","19.00","18.97","19.08","18.93","1571.00",{},"17.9464"],["201904221115","18.97","18.97","19.09","18.94","2436.00",{},"27.8278"],["201904221130","18.97","18.92","18.99","18.91","1272.00",{},"14.5308"],["201904221315","18.92","18.93","18.96","18.87","1509.00",{},"17.2382"],["201904221330","18.93","18.87","18.93","18.84","656.00",{},"7.4939"],["201904221345","18.87","18.87","18.88","18.72","1904.00",{},"21.7505"],["201904221400","18.87","18.89","18.91","18.78","1482.00",{},"16.9297"],["201904221415","18.89","18.88","18.92","18.77","1666.00",{},"19.0317"],["201904221430","18.88","18.71","18.88","18.71","1045.00",{},"11.9376"],["201904221445","18.71","18.68","18.79","18.58","3173.00",{},"36.2470"],["201904221500","18.68","18.51","18.75","18.35","3587.00",{},"40.9763"],["201904230945","18.85","18.86","19.18","18.70","8722.00",{},"99.6363"],["201904231000","18.86","18.83","18.92","18.70","3865.00",{},"44.1521"],["201904231015","18.83","18.81","18.84","18.69","2947.00",{},"33.6652"],["201904231030","18.81","18.95","19.00","18.77","4333.00",{},"49.4983"],["201904231045","18.95","18.81","18.97","18.79","2305.00",{},"26.3313"],["201904231100","18.81","18.73","18.87","18.54","3168.00",{},"36.1899"],["201904231115","18.73","18.74","18.74","18.60","2004.00",{},"22.8928"],["201904231119","18.74","18.79","18.82","18.71","330.00",{},"3.7698"]],"prec":"18.51"}}}


**/

 /*
sh600848_成交明细_20190104.xls
t1=trade.get_tick_data('600848', '2019-01-04', src='tt')
JKP get_tick_data url=http://stock.gtimg.cn/data/index.php?appn=detail&action=download&c=sh600848&d=20190104

成交时间	成交价格	价格变动	成交量(手)	成交额(元)	性质
09:25:04	19.70	-0.32	399	786030	卖盘
09:30:02	19.68	-0.02	239	470333	卖盘
09:30:05	19.62	-0.06	149	292973	卖盘
09:30:08	19.67	0.05	108	212426	买盘
09:30:11	19.69	0.02	19	37389	买盘
 * */

@SuppressWarnings("deprecation")
public class TenCentWebSource {
    private static final String TAG = TenCentWebSource.class.getName();

    private final static SimpleDateFormat sTenCentTickDateFormat
            = new SimpleDateFormat("yyyyMMdd", Locale.CHINA);
    private final static SimpleDateFormat sTenCentKLineDateFormat
            = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
    private final static SimpleDateFormat sTenCentTodayUpdateDateFormat
            = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA);
    // set default start date to 1990-01-01: year - 1900, month - 1, day = day - 1
    private final static Date sDefaultStartDate = new Date(90, 0, 0);

    private static String toTenCentCode(String netEaseCode) {
        String tsCode;
        if (netEaseCode.startsWith("0")) {
            tsCode = "sh" + netEaseCode.substring(1);
        } else {
            tsCode = "sz" + netEaseCode.substring(1);
        }
        return tsCode;
    }

    private static final Map<String, String> sTickFieldsMap = new HashMap<>();

    static {
        sTickFieldsMap.put("成交时间", "tick");
        sTickFieldsMap.put("成交价格", "price");
        sTickFieldsMap.put("价格变动", "pchg");
        sTickFieldsMap.put("成交量(手)", "volume");
        sTickFieldsMap.put("成交额(元)", "amount");
        sTickFieldsMap.put("性质", "type");
    }

    private static Map<String, Integer> getTickDataFieldsMap(String header) {
        String[] fields = header.split("\t");
        if (fields.length < 6) {
            return null;
        }
        Map<String, Integer> fieldsMap = new HashMap<>();
        for (int i = 0; i < fields.length; i++) {
            String normalName = sTickFieldsMap.get(fields[i]);
            fieldsMap.put(normalName, i);
        }
        return fieldsMap;
    }

     /*
sh600848_成交明细_20190104.xls

成交时间	成交价格	价格变动	成交量(手)	成交额(元)	性质
09:25:04	19.70	-0.32	399	786030	卖盘
09:30:02	19.68	-0.02	239	470333	卖盘
09:30:05	19.62	-0.06	149	292973	卖盘
09:30:08	19.67	0.05	108	212426	买盘
09:30:11	19.69	0.02	19	37389	买盘
 * */

    private static String downloadTickDataToRealm(String netEaseCode, Date tickDate, Realm realm) {
        String tsCode = toTenCentCode(netEaseCode);
        Map<String, String> params = new LinkedHashMap<>();
        params.put("appn", "detail");
        params.put("action", "download");
        params.put("c", tsCode);
        params.put("d", sTenCentTickDateFormat.format(tickDate));
// out-of-date
// "https://stock.gtimg.cn/data/index.php?appn=&action=&c=sh600848&d=20190104"
// new url
// 'https://stock.gtimg.cn/data/index.php?appn=detail&action=download&c=sz000403&d=20210531'
        String errorString = "ok";
        String reqUrl = "https://stock.gtimg.cn/data/index.php?" + Utils.buildUrlParameters(params);
        try {
            URL request = new URL(reqUrl);
            HttpURLConnection conn = (HttpURLConnection)request.openConnection();
            conn.setReadTimeout(3000);
            conn.addRequestProperty("Content-Type", Utils.CONTENT_TYPE);
            conn.addRequestProperty("User-Agent", Utils.HTTP_AGENT);
            conn.addRequestProperty("Referer", "stock.gtimg.cn");
            conn.setRequestMethod("GET");
            int resp = conn.getResponseCode();
            Log.i(TAG, "jkp tencent tick ResponseCod(" + resp
                    + "),URL:" + reqUrl);
            if (resp != HttpURLConnection.HTTP_OK) {
                if (resp == HttpURLConnection.HTTP_MOVED_TEMP
                        || resp == HttpURLConnection.HTTP_MOVED_PERM
                        || resp == HttpURLConnection.HTTP_SEE_OTHER) {
                    String newUrl = conn.getHeaderField("Location");
                    String cookies = conn.getHeaderField("Set-Cookie");

                    conn = (HttpURLConnection) new URL(newUrl).openConnection();
                    conn.setRequestProperty("Cookie", cookies);
                    conn.addRequestProperty("Content-Type", Utils.CONTENT_TYPE);
                    conn.addRequestProperty("User-Agent", Utils.HTTP_AGENT);
                    conn.addRequestProperty("Referer", "stock.gtimg.cn");

//                    Log.i(TAG, "jkp Redirect to URL : " + newUrl);
                    if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
                        errorString = "fail: jkp tencent tick: resp=" +  conn.getResponseCode();
                        Log.w(TAG, errorString);
                        return errorString;
                    }
                } else {
                    errorString = "fail: jkp tencent tick: resp:" +  conn.getResponseCode();
                    Log.w(TAG, errorString);
                    return errorString;
                }
            }

            BufferedReader inBr = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), Charset.forName("GBK")));
            String header = inBr.readLine(); // Get header
            Map<String, Integer> fieldsMap = getTickDataFieldsMap(header);
            if (fieldsMap == null) {
                errorString = "fail: jkp tencent tick:" + header;
                Log.w(TAG, errorString);
                return  errorString;
            }

            realm.beginTransaction();
            realm.deleteAll();
            realm.commitTransaction();

            String line;
            realm.beginTransaction();
            while ((line = inBr.readLine()) != null) {
                String[] fieldValues = line.split("\t");
                TickQuote quote = new TickQuote(fieldValues, fieldsMap);
                realm.insertOrUpdate(quote);
            }
            realm.commitTransaction();
            inBr.close();
            return errorString;
        } catch (NullPointerException e) {
            errorString = "fail jkp tencent tick for get NullPointerException";
            Log.e(TAG, errorString, e);
        } catch (IOException e) {
            errorString = "fail jkp tencent tick for get IOException";
            Log.e(TAG, errorString, e);
        }
        return errorString;
    }

    public static String downloadHistoryTickData(String netEaseCode, Date tickDate) {
        RealmConfiguration tickRealmConfig = new RealmConfiguration.Builder()
                .name(Utils.getTickRealmFile(netEaseCode, tickDate))
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(tickRealmConfig);
        // 腾讯是历史分时数据，每一天都是完整的数据
        String errorString = downloadTickDataToRealm(netEaseCode, tickDate, realm);
        realm.close();
        if (!Realm.compactRealm(tickRealmConfig)) {
            Log.w(TAG, "After TT update tick data, compact realm fail");
        }
        return errorString;
    }

    /*
    *  curl 'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?&param=sh600848,day,2019-05-23,2019-05-24,640,&r=0.28490860379037'
    {"code":0,"msg":"","data":{"sh600848":{"day":[["2019-05-23","32.900","32.500","33.190","31.700","90935.000"],
    ["2019-05-24"->date,open->"32.440",close->"32.540",high->"32.960",low->"31.000","71444.000" 手]],
    "qt":{"sh600848":["1","\u4e0a\u6d77\u4e34\u6e2f","600848","32.54","32.50","32.44","71444","34408","36982",
    "32.54","50","32.53","90","32.51","31","32.50","72","32.48","12","32.55","271","32.56","126","32.57","179","32.58","12","32.59","59","15:00:02\/32.54\/1366\/S\/4445321\/61950|14:57:02\/32.54\/40\/S\/130160\/61108|14:56:58\/32.55\/41\/B\/133444\/61095|14:56:54\/32.54\/16\/S\/52064\/61080|14:56:52\/32.54\/168\/B\/546634\/61068|14:56:49\/32.53\/1\/B\/3253\/61053","20190524153002","0.04","0.12","32.96","31.00","32.54\/71444\/230997055","71444","23100","0.91","81.58","","32.96","31.00","6.03","256.42","364.42","5.28","35.75","29.25","0.76","-392","32.33","116.56","83.72","","","1.14","23099.71"],"market":["2019-05-25 11:24:01|HK_close_\u5df2\u4f11\u5e02|SH_close_\u5df2\u4f11\u5e02|SZ_close_\u5df2\u4f11\u5e02|US_close_\u5df2\u6536\u76d8|SQ_close_\u5df2\u4f11\u5e02|DS_close_\u5df2\u4f11\u5e02|ZS_close_\u5df2\u4f11\u5e02|NEWSH_close_\u5df2\u4f11\u5e02|NEWSZ_close_\u5df2\u4f11\u5e02|NEWHK_close_\u5df2\u4f11\u5e02|NEWUS_close_\u5df2\u6536\u76d8|REPO_close_\u5df2\u4f11\u5e02|UK_close_\u5df2\u4f11\u5e02"],"zjlx":["sh600848","555.97","883.26","-327.29","-2.99","10378.05","10374.88","3.17","0.03","230997055.00","4240.15","5755.94","\u4e0a\u6d77\u4e34\u6e2f","20190524","20190523^395.56^2109.72","20190522^0.00^708.38","20190521^1689.42^1413.82","20190520^1599.20^640.76","449500.00","6414687.00","20190524150005"]},
    "mx_price":{"mx":[],"price":[]},"prec":"","version":"5"}}}

    * */
    public static List<HistoryDayQuote> getHistoryDayQuotes(String netEaseCode, float outStanding, Date start, Date end) {
        String tsCode = toTenCentCode(netEaseCode);
        String param_list = tsCode + ",day," + sTenCentKLineDateFormat.format(start)
                + "," + sTenCentKLineDateFormat.format(end) + ",640,";
        Map<String, String> params = new LinkedHashMap<>();
        params.put("param", param_list);
        params.put("r", "" + Math.random());
        //'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?&param=sh600848,day,2019-05-23,2019-05-24,640,&r=0.28490860379037'
        String reqUrl = "http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?" + Utils.buildUrlParameters(params);
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() ||
                    response.body() == null) {
                return null;
            }
            String bodyString = response.body().string();
            JSONObject resultObj = new JSONObject(bodyString);
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return null;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray dayArray = codeData.getJSONArray("day");
            List<HistoryDayQuote> hqList = new ArrayList<>();
            for (int i = 0; i < dayArray.length(); i++) {
                JSONArray dayObj = dayArray.getJSONArray(i);
                String date = dayObj.getString(0);
                int iDate = Utils.parseTTDateStringToIDate(date);
                float open = (float) dayObj.getDouble(1);
                float close = (float) dayObj.getDouble(2);
                float high = (float) dayObj.getDouble(3);
                float low = (float) dayObj.getDouble(4);
                float volume = (float) dayObj.getDouble(5);
                volume = volume * 100;
                float turnover = 0;
                if (outStanding > 0) {
                    turnover = volume / (outStanding * 10000 * 10000);
                }
                hqList.add(new HistoryDayQuote(iDate, open, high, low, close, volume,
                        0.0f, 0.0f, turnover));
            }
            return hqList;
        } catch (NullPointerException e) {
            Log.e(TAG, "Get day line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Get day line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Get day line from TenCent fail for IOException:", e);
        }
        return null;
    }

    public static int updateHistoryDayLine(String netEaseCode, Realm realm, Date endDate) {
        Date lastRecordDate;
        RealmResults<HistoryDayQuote> results = realm.where(HistoryDayQuote.class).findAll();
        lastRecordDate = sDefaultStartDate;
        if (results.size() > 0) {
            Number maxDate = results.max("date");
            if (maxDate != null) {
                lastRecordDate = Utils.getDateFromIDate(maxDate.intValue());
            }
        }
        long deltaMills = endDate.getTime() - lastRecordDate.getTime();
        if (deltaMills < Utils.MILLIS_PER_DAY) {
            return 0;
        }

        Date start = new Date(lastRecordDate.getTime() + Utils.MILLIS_PER_DAY);
        String tsCode = toTenCentCode(netEaseCode);
        String param_list = tsCode + ",day," + sTenCentKLineDateFormat.format(start)
                + "," + sTenCentKLineDateFormat.format(endDate) + ",640,";
        Map<String, String> params = new LinkedHashMap<>();
        params.put("param", param_list);
        params.put("r", "" + Math.random());
        // 股票: curl 'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?&param=sh600848,day,2019-05-23,2019-05-24,640,&r=0.28490860379037'
        // 指数: curl 'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?&param=sz399006,day,2020-08-27,2020-08-27,640,&r=0.28490860379037'
        String reqUrl = "http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?" + Utils.buildUrlParameters(params);
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() ||
                    response.body() == null) {
                return -1;
            }
            String bodyString = response.body().string();
            JSONObject resultObj = new JSONObject(bodyString);
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return -1;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray dayArray = codeData.getJSONArray("day");
            realm.beginTransaction();
            int count = 0;
            for (int i = 0; i < dayArray.length(); i++) {
                JSONArray dayObj = dayArray.getJSONArray(i);
                String date = dayObj.getString(0);
                int iDate = Utils.parseTTDateStringToIDate(date);
                float open = (float) dayObj.getDouble(1);
                float close = (float) dayObj.getDouble(2);
                float high = (float) dayObj.getDouble(3);
                float low = (float) dayObj.getDouble(4);
                float volume = (float) dayObj.getDouble(5);
                volume = volume * 100;
                float turnover = 0;
                HistoryDayQuote quote = new HistoryDayQuote(iDate, open, high, low, close, volume,
                        0.0f, 0.0f, turnover);
                if (!quote.isQualified()) {
                    continue;
                }
                realm.insertOrUpdate(quote);
                count++;
            }
            realm.commitTransaction();
            return count;
        } catch (NullPointerException e) {
            Log.e(TAG, "Update day line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Update day line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Update day line from TenCent fail for IOException:", e);
        }
        return -1;
    }

    /*
    $ curl 'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?&param=sh600848,week,2019-04-23,2019-07-06,640,&r=0.28490860379037'
    {"code":0,"msg":"","data":{"sh600848":
    {"week":[["2019-04-26","35.300","33.150","38.810","32.500","739512.000"],
    ["2019-04-30","33.700","35.220","35.550","33.500","270538.000"],
    ["2019-05-10","32.030","32.480","33.180","28.480","664346.000"],
    ["2019-05-17","32.000","32.500","35.100","31.900","650736.000"],
    ["2019-05-24","32.620","32.540","33.650","30.510","457334.000"],
    ["2019-05-31","32.650","34.530","35.740","32.100","577989.000"],
    ["2019-06-06","34.800","29.660","35.020","28.200","425624.000"],
    ["2019-06-14","29.800","29.700","31.440","28.580","369701.000"],
    ["2019-06-21","29.010","32.080","32.850","28.810","382245.000"],
    ["2019-06-28","31.900","31.130","32.610","29.900","522336.000"],
    ["2019-07-05","31.890","32.520","33.380","31.380","437691.000"]],
    "qt":{"sh600848":["1","上海临港",
    "600848","32.52","32.48","32.39","39652","19882","19744",
    "32.52","58","32.51","3","32.50","121",
    "32.49","365","32.48","49","32.53","183","32.54",
    "113","32.55","169","32.56","104","32.57","153",
    * */
    public static void updateHistoryWeekQuotes(String netEaseCode, Realm realm, Date end) {
        Date lastRecordDate = sDefaultStartDate;
        RealmResults<HistoryWeekQuote> results = realm.where(HistoryWeekQuote.class).findAll();
        if (results.size() > 0) {
            Number maxDate = results.max("date");
            if (maxDate != null) {
                int date = maxDate.intValue();
                lastRecordDate = Utils.getDateFromIDate(date);
            }
        }
        long deltaMills = end.getTime() - lastRecordDate.getTime();
        if (deltaMills < (Utils.MILLIS_PER_DAY * 7)) {
            return;
        }

        Date start = new Date(lastRecordDate.getTime() + Utils.MILLIS_PER_DAY);

        String tsCode = toTenCentCode(netEaseCode);
        String param_list = tsCode + ",week," + sTenCentKLineDateFormat.format(start)
                + "," + sTenCentKLineDateFormat.format(end) + ",640,";
        Map<String, String> params = new LinkedHashMap<>();
        params.put("param", param_list);
        params.put("r", "" + Math.random());
        String reqUrl = "http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?" + Utils.buildUrlParameters(params);
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() ||
                    response.body() == null) {
                return;
            }
            String bodyString = response.body().string();
            JSONObject resultObj = new JSONObject(bodyString);
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray weekArray = codeData.getJSONArray("week");
            realm.beginTransaction();
            for (int i = 0; i < weekArray.length(); i++) {
                JSONArray weekObj = weekArray.getJSONArray(i);
                String date = weekObj.getString(0);
                int iDate = Utils.parseTTDateStringToIDate(date);
                float open = (float) weekObj.getDouble(1);
                float close = (float) weekObj.getDouble(2);
                float high = (float) weekObj.getDouble(3);
                float low = (float) weekObj.getDouble(4);
                float volume = (float) weekObj.getDouble(5);
                volume = volume * 100;
                HistoryWeekQuote quote = new HistoryWeekQuote(iDate, open, high, low, close, volume);
                if (!quote.isQualified()) {
                    continue;
                }
                realm.insertOrUpdate(quote);
            }
            realm.commitTransaction();
        } catch (NullPointerException e) {
            Log.e(TAG, "Update week line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Update week line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Update week line from TenCent fail for IOException:", e);
        }
    }

    public static List<HistoryWeekQuote> getHistoryWeekQuotes(String netEaseCode, Date start, Date end) {
        String tsCode = toTenCentCode(netEaseCode);
        String param_list = tsCode + ",week," + sTenCentKLineDateFormat.format(start)
                + "," + sTenCentKLineDateFormat.format(end) + ",640,";
        Map<String, String> params = new LinkedHashMap<>();
        params.put("param", param_list);
        params.put("r", "" + Math.random());
        String reqUrl = "http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?" + Utils.buildUrlParameters(params);
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() ||
                    response.body() == null) {
                return null;
            }
            String bodyString = response.body().string();
            JSONObject resultObj = new JSONObject(bodyString);
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return null;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray weekArray = codeData.getJSONArray("week");
            List<HistoryWeekQuote> hwl = new ArrayList<>();
            for (int i = 0; i < weekArray.length(); i++) {
                JSONArray weekObj = weekArray.getJSONArray(i);
                String date = weekObj.getString(0);
                int iDate = Utils.parseTTDateStringToIDate(date);
                float open = (float) weekObj.getDouble(1);
                float close = (float) weekObj.getDouble(2);
                float high = (float) weekObj.getDouble(3);
                float low = (float) weekObj.getDouble(4);
                float volume = (float) weekObj.getDouble(5);
                volume = volume * 100;
                HistoryWeekQuote quote = new HistoryWeekQuote(iDate, open, high, low, close, volume);
                if (!quote.isQualified()) {
                    continue;
                }
                hwl.add(quote);
            }
            return hwl;
        } catch (NullPointerException e) {
            Log.e(TAG, "Get week line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Get week line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Get week line from TenCent fail for IOException:", e);
        }
        return null;
    }

    /* curl 'http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?&param=sh600848,month,2010-04-23,2019-07-06,640,&r=0.28490860379037'/
     *  {"code":0,"msg":"","data":{"sh600848":{"month":
     *  [["2010-04-30","12.750","11.050","13.500","11.020","1295017.710"],
     *  ["2010-05-31","10.510","9.930","11.510","8.600","603320.190"],
     *  ["2010-06-30","9.730","8.520","10.490","8.500","401859.780"],
     *  ["2010-07-30","8.760","10.230","10.820","7.900","889948.120"],
     * */

    public static void updateHistoryMonthQuotes(String netEaseCode, Realm realm, Date end) {
        Date lrd = sDefaultStartDate;
        RealmResults<HistoryMonthQuote> results = realm.where(HistoryMonthQuote.class).findAll();
        if (results.size() > 0) {
            Number maxDate = results.max("date");
            if (maxDate != null) {
                int date = maxDate.intValue();
                lrd = Utils.getDateFromIDate(date);
            }
        }

//        long deltaMills = end.getTime() - lastRecordDate.getTime();
//        if (deltaMills < (Utils.MILLIS_PER_DAY * 27)) {
//            return;
//        }
        int deltaMonth = (end.getYear() - lrd.getYear()) * 12 +
                (end.getMonth() - lrd.getMonth());
        if (deltaMonth <= 0) {
            return;
        }

        Date start = new Date(lrd.getTime() + Utils.MILLIS_PER_DAY);
        String tsCode = toTenCentCode(netEaseCode);
        String param_list = tsCode + ",month," + sTenCentKLineDateFormat.format(start)
                + "," + sTenCentKLineDateFormat.format(end) + ",640,";
        Map<String, String> params = new LinkedHashMap<>();
        params.put("param", param_list);
        params.put("r", "" + Math.random());
        String reqUrl = "http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?" + Utils.buildUrlParameters(params);
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() || response.body() == null) {
                return;
            }
            String bodyString = response.body().string();
            JSONObject resultObj = new JSONObject(bodyString);
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray monthArray = codeData.getJSONArray("month");
            realm.beginTransaction();
            for (int i = 0; i < monthArray.length(); i++) {
                JSONArray monthObj = monthArray.getJSONArray(i);
                String date = monthObj.getString(0);
                int iDate = Utils.parseTTDateStringToIDate(date);
                float open = (float) monthObj.getDouble(1);
                float close = (float) monthObj.getDouble(2);
                float high = (float) monthObj.getDouble(3);
                float low = (float) monthObj.getDouble(4);
                float volume = (float) monthObj.getDouble(5);
                volume = volume * 100;
                HistoryMonthQuote quote = new HistoryMonthQuote(iDate, open, high, low, close, volume);
                if (!quote.isQualified()) {
                    continue;
                }
                realm.insertOrUpdate(quote);
            }
            realm.commitTransaction();
        } catch (NullPointerException e) {
            Log.e(TAG, "Update week line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Update week line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Update week line from TenCent fail for IOException:", e);
        }
    }

    public static List<HistoryMonthQuote> getHistoryMonthQuotes(String netEaseCode, Date start, Date end) {
        String tsCode = toTenCentCode(netEaseCode);
        String param_list = tsCode + ",month," + sTenCentKLineDateFormat.format(start)
                + "," + sTenCentKLineDateFormat.format(end) + ",640,";
        Map<String, String> params = new LinkedHashMap<>();
        params.put("param", param_list);
        params.put("r", "" + Math.random());
        String reqUrl = "http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?" + Utils.buildUrlParameters(params);
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() ||
                    response.body() == null) {
                return null;
            }
            String bodyString = response.body().string();
            JSONObject resultObj = new JSONObject(bodyString);
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return null;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray dayArray = codeData.getJSONArray("month");
            List<HistoryMonthQuote> hwl = new ArrayList<>();
            for (int i = 0; i < dayArray.length(); i++) {
                JSONArray day = dayArray.getJSONArray(i);
                String date = day.getString(0);
                int iDate = Utils.parseTTDateStringToIDate(date);
                float open = (float) day.getDouble(1);
                float close = (float) day.getDouble(2);
                float high = (float) day.getDouble(3);
                float low = (float) day.getDouble(4);
                float volume = (float) day.getDouble(5);
                volume = volume * 100;
                HistoryMonthQuote quote = new HistoryMonthQuote(iDate, open, high, low, close, volume);
                if (!quote.isQualified()) {
                    continue;
                }
                hwl.add(quote);
            }
            return hwl;
        } catch (NullPointerException e) {
            Log.e(TAG, "Get week line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Get week line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Get week line from TenCent fail for IOException:", e);
        }
        return null;
    }

    /*
     curl 'http://ifzq.gtimg.cn/appstock/app/kline/mkline?param=sh600848,m60,,640&_var=m60_today&r=0.6715938253235771'
m60_today={"code":0,"msg":"","data":{"sh600848":{"qt":{"sh600848":[
 3\/32.52\/594\/S\/1931688\/77173|GP-A"],"market":["2019-07-06 12:45:01|HK_close_\u5df2\u4f11\u5e02|SH_close_
  5e02"],"zjlx":["sh600848","53.13","20190704^508.77^340.15","000.00","3650854.00","20190705150006"]},
  "m60":[["201901031400","20.42","20.42","20.44","20.21","6022.00",{},"7.6419"],["201901031500","20.42","20.02","20.43","20.00","17667.00",{},"22.4193"],
  ["201901041030","19.70","20.08","20.23","19.60","13326.00",{},"16.9106"],["201901041130","20.08","20.37","20.40","20.06","7220.00",{},"9.1621"],  * */

    public static void updateHistoryHourQuotes(String netEaseCode, Realm realm, Date end) {
        int count;
        RealmResults<HistoryHourQuote> results =
                realm.where(HistoryHourQuote.class).
                        sort("date", Sort.ASCENDING).findAll();
        if (results.size() <= 0) {
            count = 640; // 640 is the max value
        } else {
            HistoryHourQuote lhq = results.get(results.size() - 1);
            String ld = "null";
            if (lhq != null)
                ld = lhq.getDate();
            try {
                Date ldate = Utils.sDateMinuteFormat.parse(ld);
                long deltaMills = end.getTime() - ldate.getTime();
                int hour = ldate.getHours();
                if (deltaMills < Utils.MILLIS_PER_DAY && hour >= 15) {
                    return;
                }
                long days = deltaMills / Utils.MILLIS_PER_DAY;
                count = Math.min(640, ((int) days + 1) * 4);
            } catch (ParseException e) {
                count = 640;
            }
        }

        String tsCode = toTenCentCode(netEaseCode);
        String param_list = String.format(Locale.CHINA, "param=%s,m60,,%d&_var=m60_today&r=%s",
                tsCode, count, "" + Math.random());
        String reqUrl = "http://ifzq.gtimg.cn/appstock/app/kline/mkline?" + param_list;
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() ||
                    response.body() == null) {
                return;
            }
            String bs = response.body().string();
            JSONObject resultObj = new JSONObject(
                    bs.substring(bs.indexOf("{"), bs.lastIndexOf("}") + 1));
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray dayArray = codeData.getJSONArray("m60");
            realm.beginTransaction();
            for (int i = 0; i < dayArray.length(); i++) {
                JSONArray day = dayArray.getJSONArray(i);
                String date = day.getString(0);
                if (!Utils.isRegularHourDateTime(date)) {
                    continue;
                }
                float open = (float) day.getDouble(1);
                float close = (float) day.getDouble(2);
                float high = (float) day.getDouble(3);
                float low = (float) day.getDouble(4);
                float volume = (float) day.getDouble(5);
                volume = volume * 100;
                HistoryHourQuote quote = new HistoryHourQuote(date, open, high, low, close, volume);
                if (!quote.isQualified()) {
                    continue;
                }
                realm.insertOrUpdate(quote);
            }
            realm.commitTransaction();
        } catch (NullPointerException e) {
            Log.e(TAG, "Update hour line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Update hour line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Update hour line from TenCent fail for IOException:", e);
        }
    }

    public static List<HistoryHourQuote> getHistoryHourQuotes(String netEaseCode,
                                                       Date start,
                                                       Date end) {
        int count;
        long deltaMills = end.getTime() - start.getTime();
        long days = deltaMills / Utils.MILLIS_PER_DAY;
        count = Math.min(640, ((int) days + 1) * 4);

        String tsCode = toTenCentCode(netEaseCode);
        String param_list = String.format(Locale.CHINA,
                "param=%s,m60,,%d&_var=m60_today&r=%s",
                tsCode, count, "" + Math.random());
        String reqUrl = "http://ifzq.gtimg.cn/appstock/app/kline/mkline?" + param_list;
        try {
            OkHttpClient okClient = new OkHttpClient();
            Request request = new Request.Builder().url(reqUrl).get().build();
            Response response = okClient.newCall(request).execute();
            if (!response.isSuccessful() ||
                    response.body() == null) {
                return null;
            }
            String bs = response.body().string();
            JSONObject resultObj = new JSONObject(
                    bs.substring(bs.indexOf("{"), bs.lastIndexOf("}") + 1));
            int resultCode = Integer.parseInt(resultObj.getString("code"));
            if (resultCode != 0) {
                return null;
            }
            JSONObject data = resultObj.getJSONObject("data");
            JSONObject codeData = data.getJSONObject(tsCode);
            JSONArray dayArray = codeData.getJSONArray("m60");
            List<HistoryHourQuote> lhs = new ArrayList<>();
            for (int i = 0; i < dayArray.length(); i++) {
                JSONArray day = dayArray.getJSONArray(i);
                String date = day.getString(0);
                float open = (float) day.getDouble(1);
                float close = (float) day.getDouble(2);
                float high = (float) day.getDouble(3);
                float low = (float) day.getDouble(4);
                float volume = (float) day.getDouble(5);
                volume = volume * 100;
                HistoryHourQuote quote = new HistoryHourQuote(date, open, high, low, close, volume);
                if (!quote.isQualified()) {
                    continue;
                }
                lhs.add(quote);
            }
            return lhs;
        } catch (NullPointerException e) {
            Log.e(TAG, "Get hour Line from TenCent fail for NullPointerException:", e);
        } catch (JSONException e) {
            Log.e(TAG, "Get hour Line from TenCent fail for JSONException:", e);
        } catch (IOException e) {
            Log.e(TAG, "Get hour Line from TenCent fail for IOException:", e);
        }
        return null;
    }


/*
*
*
一、要获取最新行情，以五粮液为例，访问数据接口如下：（注：查询多个股票，用逗号,隔开代码）
http://qt.gtimg.cn/q=sz000858
返回数据：
v_sz000858="51~五粮液~000858~27.78~27.60~27.70~417909~190109~227800~27.78~492~27.77~332~27.76~202~27.75~334
~27.74~291~27.79~305~27.80~570~27.81~269~27.82~448~27.83~127
~15:00:13/27.78/4365/S/12124331/24602|14:56:55/27.80/14/S/38932/24395|14:56:52/27.81/116/B/322585/24392|14:56:49/27.80/131/S/364220/24385|14:56:46/27.81/5/B/13905/24381|14:56:43/27.80/31/B/86199/24375
~20121221150355~0.18~0.65~28.11~27.55~27.80/413544/1151265041~417909~116339~1.10~10.14~~28.11~27.55~2.03~1054.39~1054.52~3.64~30.36~24.84~";
v_sz000002="51~万  科Ａ~000002~16.80~16.84~16.93~696804~379543~317261
~16.80~790~16.79~122~16.78~650~16.77~365~16.76~325
~16.81~598~16.82~217~16.83~586~16.84~263~16.85~442
~~20220902161436~-0.04~-0.24~16.95~16.57~16.80/696804/1165902392~696804~116590~0.72~8.24~~16.95~16.57~2.26~1632.52~1953.96~0.83~18.52~15.16~0.72~146~16.73~7.99~8.67
~~~1.20~116590.2392~0.0000~0~ ~GP-A~-10.60~6.13~5.77~10.12~2.13~22.12~13.46~4.73~8.45~-0.54~9717360740~11630709471~3.35~-10.83~9717360740~~~-16.96~-0.18~";
v_sh000001="1~上证指数~000001~3186.48~3184.98~3189.64~250456911~125228456~125228456~0.00~0~0.00~0~0.00~0~0.00~0~0.00~0~0.00~0~0.00~0~0.00~0~0.00~0~0.00~0
~~20220902155910~1.50~0.05~3198.28~3173.79~3186.48/250456911/313337604115~250456911~31333760~0.59~12.40~~3198.28~3173.79~0.77~394414.70~502084.24~0.00~-1~-1~0.82~0
~3186.94~~~~~~31333760.4115~0.0000~0~ ~ZS~-12.45~-1.54~~~~3723.85~2863.65~-2.20~-1.26~-2.99~4066128123312~~-9.10~-12.40~4066128123312~~~-11.41~-0.03~";

以 ~ 分割字符串中内容，下标从0开始，参数依次为
0: 未知; 1: 名字; 2: 代码; 3: 当前价格;4: 昨收; 5: 今开6: 成交量（手）7: 外盘 8: 内盘
9: 买一 10: 买一量（手）11-18: 买二 买五
19: 卖一 20: 卖一量 21-28: 卖二 卖五
29: 最近逐笔成交
30: 时间 31: 涨跌 32: 涨跌% 33: 最高 34: 最低 35: 价格/成交量（手）/成交额
36: 成交量（手）37: 成交额（万）38: 换手率 39: 市盈率 40: 41: 最高 42: 最低 43: 振幅
44: 流通市值 45: 总市值 46: 市净率 47: 涨停价 48: 跌停价

* */

    private static TodayQuote parseTenCentToTodayQuote(String quote) {
        String[] fields = quote.split("~");
        if (fields.length < 43)
            return null;
        String netEaseCode = fields[2];
        if (fields[0].contains("sh")) {
            netEaseCode = "0" + netEaseCode;
        } else if (fields[0].contains("sz")) {
            netEaseCode = "1" + netEaseCode;
        } else {
            return null;
        }

        Date update;
        float open, price, high, low, yesterdayClose, volume, percent, amount;
        float bid1, bid2, bid3, bid4, bid5, ask1, ask2, ask3, ask4, ask5;
        int   bidVol1, bidVol2, bidVol3, bidVol4, bidVol5, askVol1, askVol2, askVol3, askVol4, askVol5;
        try {
            price = Float.parseFloat(fields[3]);
            yesterdayClose = Float.parseFloat(fields[4]);
            open = Float.parseFloat(fields[5]);

            bid1 = Float.parseFloat(fields[9]);  bidVol1 = Integer.parseInt(fields[10]); // 腾讯单位是手
            bid2 = Float.parseFloat(fields[11]); bidVol2 = Integer.parseInt(fields[12]);
            bid3 = Float.parseFloat(fields[13]); bidVol3 = Integer.parseInt(fields[14]);
            bid4 = Float.parseFloat(fields[15]); bidVol4 = Integer.parseInt(fields[16]);
            bid5 = Float.parseFloat(fields[17]); bidVol5 = Integer.parseInt(fields[18]);

            ask1 = Float.parseFloat(fields[19]); askVol1 = Integer.parseInt(fields[20]); // 腾讯单位是手
            ask2 = Float.parseFloat(fields[21]); askVol2 = Integer.parseInt(fields[22]);
            ask3 = Float.parseFloat(fields[23]); askVol3 = Integer.parseInt(fields[24]);
            ask4 = Float.parseFloat(fields[25]); askVol4 = Integer.parseInt(fields[26]);
            ask5 = Float.parseFloat(fields[27]); askVol5 = Integer.parseInt(fields[28]);

            update = sTenCentTodayUpdateDateFormat.parse(fields[30]);
            percent = Float.parseFloat(fields[32]) / 100.0f; // 网易应该除了100
            high = Float.parseFloat(fields[33]);
            low = Float.parseFloat(fields[34]);
            volume = Float.parseFloat(fields[36]) * 100.0f; // 网易单位是股，腾讯单位是手(100股)
            amount = Float.parseFloat(fields[37]) * 10000.0f;  //  网易单位是元，腾讯单位是万元

        } catch (Exception e) {
            Log.e(TAG, "Parse " + netEaseCode + " found exception:", e);
            return null;
        }
        TodayQuote todayQuote = new TodayQuote();

        todayQuote.setNecode(netEaseCode);
        todayQuote.setUpdate(TodayQuote.sUpdateDateFormat.format(update));
        todayQuote.setOpen(open);
        todayQuote.setPrice(price);
        todayQuote.setHigh(high);
        todayQuote.setLow(low);
        todayQuote.setYestclose(yesterdayClose);
        todayQuote.setVolume(volume);
        todayQuote.setPercent(percent);
        todayQuote.setTurnover(amount);

        todayQuote.setBuys(String.format(Locale.CHINA,
                " 买1:%.2f %d\n 买2:%.2f %d\n 买3:%.2f %d\n 买4:%.2f %d\n 买5:%.2f %d",
                bid1, bidVol1, bid2, bidVol2, bid3, bidVol3, bid4, bidVol4, bid5, bidVol5));
        todayQuote.setSells(String.format(Locale.CHINA,
                " 卖1:%.2f %d\n 卖2:%.2f %d\n 卖3:%.2f %d\n 卖4:%.2f %d\n 卖5:%.2f %d",
                ask1, askVol1, ask2, askVol2, ask3, askVol3, ask4, askVol4, ask5, askVol5));

        return todayQuote;
    }


    static ArrayList<String> fetchTodayQuotes(
            List<String> codeList,
            Realm realm) {
        if (codeList.size() < 1)
            return null;

        StringBuilder sbUrl = new StringBuilder("http://qt.gtimg.cn/q=");
        for (String netEaseCode : codeList) {
            String tsCode = toTenCentCode(netEaseCode);
            sbUrl = sbUrl.append(tsCode).append(",");
        }
        int timeoutMilliSeconds = 300 * 1000;
        try {
            URL u = new URL(sbUrl.toString());
            HttpURLConnection c = (HttpURLConnection) u.openConnection();
            c.setRequestMethod("GET");
            c.setRequestProperty("Content-length", "0");
            c.setUseCaches(false);
            c.setAllowUserInteraction(false);
            c.setConnectTimeout(timeoutMilliSeconds);
            c.setReadTimeout(timeoutMilliSeconds);
            c.connect();
            if (HttpURLConnection.HTTP_OK == c.getResponseCode()) {
                BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
                StringBuilder sb = new StringBuilder();
                String line;
                while ((line = br.readLine()) != null) {
                    sb.append(line).append("\n");
                }
                br.close();
                String[] stock_quotes = sb.toString().split(";\n");
                ArrayList<String> resultCodeList = new ArrayList<>();
                for (String quote : stock_quotes) {
                    TodayQuote todayQuote = parseTenCentToTodayQuote(quote);
                    if (todayQuote == null) {
                        Log.i(TAG, "fail to parse quote:" + quote);
                        continue;
                    }
                    resultCodeList.add(todayQuote.getNecode());
                    realm.beginTransaction();
                    realm.insertOrUpdate(todayQuote);
                    realm.commitTransaction();
                }
                return resultCodeList;
            }
            c.disconnect();
        } catch (InterruptedIOException e) {
            Log.e(TAG, "Fetch io error at url:" + sbUrl.toString());
        } catch (Exception e) {
            Log.e(TAG, "Fetch market quotes fail for unknown exception:", e);
        }

        return null;
    }

}
